#include <Arduino.h>
#include <some_config.h>
#include "PubSubClient.h" ////A client library for MQTT messaging.
#include <WiFiClient.h>
#include <WiFi.h>
#include <string.h>
#include "aliyun_client.h"
#include <DallasTemperature.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>

// I2C 引脚
#define WIRE_SCL 18
#define WIRE_SDA 19
#define TM601_I2C_ADDRESS 0x40
#define OLED_I2C_ADDRESS 0x3C

// 温度传感器引脚
#define ONE_WIRE_BUS 13

TwoWire I2Cone = TwoWire(1);
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &I2Cone);

OneWire oneWire(ONE_WIRE_BUS);       // 声明
DallasTemperature sensors(&oneWire); // 声明

TaskHandle_t aliyun_task_handle;
TaskHandle_t oled_task_handle;
TaskHandle_t sampling_task_handle;

#define power_ctrl_pin 25

float temperature = 0;
float waterVolume_mm = 0;

float get_tempC();
void oled_display();
uint16_t get_WaterVolume_mm();
float calculateVariance(float arr[], int size);

// 连接wifi
void wifiInit()
{
  WiFi.begin(WIFI_SSID, WIFI_PASSWD);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
    Serial.printf("WiFi not Connect,SSID: %s\r\n", WIFI_SSID);
  }
  Serial.println("WiFi Connected");
}

void aliyun_data_refresh()
{
  xTaskNotify(aliyun_task_handle, 1, eNoAction);
}

void oled_task(void *pvParameters)
{

  while (1)
  {

    display.setTextColor(WHITE); // 开像素点发光
    display.setCursor(0, 0);
    display.clearDisplay();
    display.printf("\n tmp:%.2f\n", temperature);
    display.printf(" vol:%d\n", (int)waterVolume_mm);
    display.display();
    bsp_delay(1000);
  }
}

void sampling_task(void *pvParameters)
{
#define volume_size 20
  static float waterVolume_buff[volume_size] = {0};
  static float Variance;
  static uint16_t index = 0;
  for (int i = 0; i < volume_size; i++)
  {
    if (i)
    {
      waterVolume_buff[i] = waterVolume_buff[0];
      continue;
    }
    waterVolume_buff[i] = get_WaterVolume_mm();
  }
  while (1)
  {

    waterVolume_buff[index % volume_size] = get_WaterVolume_mm();
    Variance = calculateVariance(waterVolume_buff, volume_size);
    if(Variance<1)  waterVolume_mm=waterVolume_buff[index % volume_size];
    if(0) Serial.printf("Volume v:%f\tvolume:%f\n", Variance,waterVolume_buff[index % volume_size]);

  
    index++;  
    bsp_delay(100);
  }
}

void aliyun_task(void *pvParameters)
{
  BaseType_t ensure = NULL;

  while (mqttCheckConnect() == -1);
  for (;;)
  {
    aliyun_mqtt_send_data(TEMPERATURE, temperature);
    aliyun_mqtt_send_data(QUANTITY_MM, (int)waterVolume_mm);
    ensure = ulTaskNotifyTake(pdTRUE, ALIYUN_UPDATE_MAX_WAIT_TIME);
  }
}

void power_task(void *pvParameters)
{
  while (1)
  {
    bsp_delay(19000);
    digitalWrite(power_ctrl_pin, LOW);
    bsp_delay(1000);
    digitalWrite(power_ctrl_pin, HIGH);
  }
}

void setup()
{
  Serial.begin(115200);
  pinMode(power_ctrl_pin, OUTPUT);
  digitalWrite(power_ctrl_pin, HIGH);

  void print_some();
  print_some();
  wifiInit();
  mqtt_init();

  I2Cone.begin(WIRE_SDA, WIRE_SCL, 400000);
  sensors.begin(); // 初始化总线
  // 初始化显示屏
  display.begin(SSD1306_SWITCHCAPVCC, OLED_I2C_ADDRESS);
  // 清屏
  display.clearDisplay();
  // 设置字体大小
  display.setTextSize(2);
  display.setTextColor(INVERSE);

  xTaskCreate(aliyun_task, "aliyun", 10000, NULL, 2, &aliyun_task_handle);
  xTaskCreate(power_task, "power", 10000, NULL, 2, NULL);
  xTaskCreate(oled_task, "oled", 10000, NULL, 2, &oled_task_handle);
  xTaskCreate(sampling_task, "sampling", 10000, NULL, 2, &sampling_task_handle);
}

void loop()
{
  temperature = get_tempC();
  bsp_delay(1000);
}

float get_tempC()
{
  sensors.requestTemperatures();
  float tempC = sensors.getTempCByIndex(0);
  if (tempC != DEVICE_DISCONNECTED_C) // 如果获取到的温度正常
  {
    return tempC;
  }
  else
  {
    return -1;
  }
}

void TM601_writeRegister(uint8_t address, uint8_t data)
{
  I2Cone.beginTransmission(TM601_I2C_ADDRESS);
  I2Cone.write(address);
  I2Cone.write(data);
  I2Cone.endTransmission();
}

void TM601_burstRead(uint8_t *buffer, uint8_t length)
{
  I2Cone.beginTransmission(TM601_I2C_ADDRESS);
  I2Cone.write(0x00);
  I2Cone.endTransmission();
  I2Cone.requestFrom((uint8_t)TM601_I2C_ADDRESS, length, false);

  uint8_t idx = 0;
  while (I2Cone.available())
  {
    buffer[idx++] = I2Cone.read();
  }
}

uint16_t get_WaterVolume_mm()
{
  byte rx_buf[7] = {0};
  TM601_burstRead(rx_buf, 4);
  return map(rx_buf[0], 0, 255, 0, 81);
}

// 计算数组的方差
float calculateVariance(float arr[], int size)
{
  float sum = 0;
  float mean = 0;
  float variance = 0;

  // 计算数组的平均值
  for (int i = 0; i < size; ++i)
  {
    sum += arr[i];
  }
  mean = sum / size;

  // 计算方差
  for (int i = 0; i < size; ++i)
  {
    variance += pow(arr[i] - mean, 2);
  }
  variance /= size;

  return variance;
}
